﻿using System;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using System.Camera.Monitor;
using System.Camera.Broadcast;

namespace ViewCam
{
    public partial class CameraIPForm : Form
    {
        public CameraIPForm()
        {
            InitializeComponent();
        }

        #region Properties
        public string password { get; set; }

        public string title { get; set; }

        public string type { get; set; }

        public string url { get; set; }

        public string username { get; set; }

        public DateTime endTime { get; set; }

        public string RecordPath { get; set; }

        public DateTime startTime { get; set; }

        TimeForm timeSched;

        public Int32 AutoNotifyStop { get; set; }

        public Int32 AutoRecordStop { get; set; }

        public Int32 BeepDura { get; set; }

        public Int32 BeepFreq { get; set; }
        #endregion

        #region Declarations
        CameraClient client;
        ipCameraMonitor ipmoncam;
        ViewCamHelper viewcamModule;
        MJPEGStream mjpegStream;
        JPEGStream jpegStream;
        #endregion

        #region Controls

        /// <summary>
        /// Handles the Click event of the btnClose control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnClose_Click(object sender, EventArgs e)
        {
            CloseCurrentVideoSource();
            Shutdown();
            this.Close();
        }

        /// <summary>
        /// Handles the FormClosing event of the CameraIPForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void CameraIPForm_FormClosing(object sender, EventArgs e)
        {
            CloseCurrentVideoSource();
            Shutdown();
        }
        
        /// <summary>
        /// Handles the Load event of the CameraIPForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void CameraIPForm_Load(object sender, EventArgs e)
        {
            try
            {
                this.Text = title;
                setupStream(type);
                setupOptions(false);
                LoadToolTips();
                SetTheme();
                SetStatus("Ready");
            }
            catch (Exception)
            {}
            
        }

        /// <summary>
        /// Handles the Click event of the btnConnect control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (this.txtIPAddress.Text != "")
            {
                if (this.btnConnect.Text == "Connect")
                {
                    this.client.Connect(txtIPAddress.Text, 8080);
                    this.btnConnect.Text = "Disconnect";
                    SetStatus("Transmit Data Disconnected.");
                }
                else
                {
                    this.client.Disconnect();
                    this.btnConnect.Text = "Connect";
                    SetStatus("Transmit Data Connect.");
                }
            }
            else
            {
                MessageBox.Show("No IP Address!", "View Cam", MessageBoxButtons.OK);
            }
        }

        /// <summary>
        /// Handles the Click event of the btnRecord control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnRecord_Click(object sender, EventArgs e)
        {
            if (this.ipmoncam.IsRecording)
            {
                this.ipmoncam.StopRecording();
                this.ipmoncam.forceRecord = false;
                this.btnRecord.Text = "Record";
                SetStatus("Manual Record Started.");
            }
            else
            {
                this.ipmoncam.StartRecording();
                this.ipmoncam.forceRecord = true;
                this.btnRecord.Text = "Stop";
                SetStatus("Manual Record Stopped.");
            }
        }

        /// <summary>
        /// Handles the Click event of the btnSchedule control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnSchedule_Click(object sender, EventArgs e)
        {
            timeSched = new TimeForm();
            timeSched.camIPForm = this;
            timeSched.ShowDialog();

            if (startTime != null & endTime != null)
            {
                if (startTime < endTime)
                {
                    SetStatus("Scheduled Recording: Starts at " + startTime.ToLongTimeString() + " | Ends at " + endTime.ToLongTimeString());
                    DisableControlOnSchedule();
                    EnableTimerOnSchedule();
                }
                else
                {
                    SetStatus("Time Not Properly Set. Start Time must be greater than Time Right Now and End Time.");
                }
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the AutoRecord control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void AutoRecord_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox)sender).Checked)
            {
                this.toggleOption(1, true);
                SetStatus("Automatic Recording Enabled.");
            }
            else
            {
                this.toggleOption(1, false);
                SetStatus("Automatic Recording Disabled.");
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the BeepOnMotion control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void BeepOnMotion_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox)sender).Checked)
            {
                this.toggleOption(2, true);
                SetStatus("Beep On Motion Enabled.");
            }
            else
            {
                this.toggleOption(2, false);
                SetStatus("Beep On Motion Disabled.");
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the MotionDetection control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void MotionDetection_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox)sender).Checked)
            {
                this.toggleOption(0, true);
                SetStatus("Motion Detection Enabled.");
            }
            else
            {
                this.toggleOption(0, false);
                SetStatus("Motion Detection Disabled.");
            }
        }

        /// <summary>
        /// Handles the Tick event of the timer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void timer_Tick(object sender, EventArgs e)
        {
            if (DateTime.Now.ToLongTimeString() == startTime.ToLongTimeString())
            {
                this.ipmoncam.StartRecording();
                this.ipmoncam.forceRecord = true;
            }

            if (DateTime.Now.ToLongTimeString() == endTime.ToLongTimeString())
            {
                this.ipmoncam.StopRecording();
                this.ipmoncam.forceRecord = false;
                DisableTimerOnSchedule();
                EnableControlOnSchedule();
                SetStatus("Scheduled Recording Completed.");
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Setups the stream.
        /// </summary>
        /// <param name="streamType">Type of the stream.</param>
        private void setupStream(string streamType)
        {
            if (streamType == "JPEG")
            {
                jpegStream = new JPEGStream(url);
                jpegStream.Login = username;
                jpegStream.Password = password;
                this.ipmoncam = new ipCameraMonitor(jpegStream, this.videoSourcePlayer, this.picBox);
            }
            else if (streamType == "MJPEG")
            {
                mjpegStream = new MJPEGStream(url);
                mjpegStream.Login = username;
                mjpegStream.Password = password;
                this.ipmoncam = new ipCameraMonitor(mjpegStream, this.videoSourcePlayer, this.picBox);
            }

            String[] ipURL;
            url = url.Replace("http://","");
            ipURL = url.Split('/');
            url = ipURL[0];

            this.ipmoncam.RecordingPath = RecordPath;
            this.ipmoncam.URL = url;
            this.ipmoncam.BeepFreq = BeepFreq;
            this.ipmoncam.BeepDura = BeepDura;
            this.ipmoncam.AutoRecordStop = AutoRecordStop;
            this.ipmoncam.AutoNotifyStop = AutoNotifyStop;

            this.client = new CameraClient(this.picBox);
            this.client.CameraOutputSize = this.picBox.Size;
        }

        /// <summary>
        /// Shutdowns this instance.
        /// </summary>
        public void Shutdown()
        {
            this.ipmoncam.StopRecording();
            this.ipmoncam.StopCapture();
        }

        /// <summary>
        /// Disables the control on schedule.
        /// </summary>
        private void DisableControlOnSchedule()
        {
            this.btnRecord.Enabled = false;
            //this.btnClose.Enabled = false;
            this.grpOptions.Enabled = false;
        }

        /// <summary>
        /// Disables the timer on schedule.
        /// </summary>
        private void DisableTimerOnSchedule()
        {
            timer.Enabled = false;
        }

        /// <summary>
        /// Enables the control on schedule.
        /// </summary>
        private void EnableControlOnSchedule()
        {
            this.btnRecord.Enabled = true;
            //this.btnClose.Enabled = true;
            this.grpOptions.Enabled = true;
        }

        /// <summary>
        /// Enables the timer on schedule.
        /// </summary>
        private void EnableTimerOnSchedule()
        {
            timer.Interval = 100;
            timer.Enabled = true;
        }

        /// <summary>
        /// Sets the status.
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetStatus(string message)
        {
            this.lblCamStatus.Text = message;
        }

        /// <summary>
        /// Sets the theme.
        /// </summary>
        private void SetTheme()
        {
            viewcamModule = new ViewCamHelper();
            this.BackColor = viewcamModule.SetThemeColor(lblStatus);
        }

        /// <summary>
        /// Setups the options.
        /// </summary>
        /// <param name="value">if set to <c>true</c> [value].</param>
        private void setupOptions(bool value)
        {
            this.BeepOnMotion.Enabled = value;
            this.AutoRecord.Enabled = value;

            if (value == false)
            {
                this.BeepOnMotion.Checked = value;
                this.AutoRecord.Checked = value;
            }
        }

        /// <summary>
        /// Loads the tool tips.
        /// </summary>
        private void LoadToolTips()
        {
            ShowToolTip("Records video via a Scheduled Time.", btnSchedule);
            ShowToolTip("Records video via User Dependent.", btnRecord);
            ShowToolTip("Relays the video to the desired IP address.", btnConnect);
            ShowToolTip("Closes this window. Dropping any connection.", btnClose);
            ShowToolTip("Input IP Address.", txtIPAddress);
            ShowToolTip("Toggle checkbox to Detect Motion.", MotionDetection);
            ShowToolTip("Toggle checkbox to beep if motion is detected.", BeepOnMotion);
            ShowToolTip("Toggle checkbox to automatically record if motion is detected.", AutoRecord);
        }

        /// <summary>
        /// Shows the tool tip.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="btn">The BTN.</param>
        private void ShowToolTip(string msg, Control btn)
        {
            viewcamModule = new ViewCamHelper();
            viewcamModule.EnableToolTip(msg, btn, toolTip);
        }

        /// <summary>
        /// Toggles the option.
        /// </summary>
        /// <param name="optionIndex">Index of the option.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        private void toggleOption(int optionIndex, bool value)
        {
            switch (optionIndex)
            {
                case 0:
                    this.ipmoncam.MotionDetection = value;
                    setupOptions(value);
                    break;
                case 1:
                    this.ipmoncam.RecordOnMotion = value;
                    break;
                case 2:
                    this.ipmoncam.BeepOnMotion = value;
                    break;
            }
        }

        // Close video source if it is running
        /// <summary>
        /// Closes the current video source.
        /// </summary>
        public void CloseCurrentVideoSource()
        {
            if (videoSourcePlayer.VideoSource != null)
            {
                videoSourcePlayer.SignalToStop();

                // wait ~ 3 seconds
                for (int i = 0; i < 30; i++)
                {
                    if (!videoSourcePlayer.IsRunning)
                        break;
                    System.Threading.Thread.Sleep(100);
                }

                if (videoSourcePlayer.IsRunning)
                {
                    videoSourcePlayer.Stop();
                }

                videoSourcePlayer.VideoSource = null;
            }
        }
        #endregion
    }
}
